home *** CD-ROM | disk | FTP | other *** search
/ Tricks of the Mac Game Programming Gurus / TricksOfTheMacGameProgrammingGurus.iso / CodeWarrior Lite / Metrowerks C⁄C++ Lite / Libraries / Runtime / Common Sources / MWException.cp < prev    next >
Encoding:
Text File  |  1995-04-18  |  16.6 KB  |  486 lines  |  [TEXT/MMCC]

  1. /************************************************************************/
  2. /*    Project...:    Standard C++ Library                                    */
  3. /*    Name......:    MWException.cp                                            */
  4. /*    Purpose...:    portable exception handling                                */
  5. /*  Copyright.: ©Copyright 1993-95 by metrowerks inc                    */
  6. /************************************************************************/
  7.  
  8. #include <Types.h>
  9. #include <stdlib.h>
  10. #include <CPlusLib.h>
  11. #include <exception.h>
  12. #include <MWException.h>
  13.  
  14. #ifndef __MC68K__        //    defined in 68K startup code
  15.  
  16.     DestructorChain        *__global_destructor_chain;    // chain of global objects that need destruction
  17.     ExceptionElement    *__local_destructor_chain;    // chain of local objects that need destruction
  18.  
  19. #endif
  20.  
  21. static char        catch_buffer[CATCH_BUFSIZE];
  22. void            *__catch_buffer = (void *)catch_buffer;
  23. void            *__catch_var_pointer;
  24. char            *__throw_type;
  25.  
  26. static terminate_handler    thandler;        //    pointer to terminate handler function
  27. static unexpected_handler    uhandler;        //    pointer to unexpected handler function
  28.  
  29. /************************************************************************/
  30. /*    Purpose..:     Set a terminate handler function                        */
  31. /*    Input....:    pointer to terminate handler function                    */
  32. /*    Return...:    ---                                                        */
  33. /************************************************************************/
  34. extern terminate_handler set_terminate(terminate_handler handler)
  35. {
  36.     terminate_handler old=thandler; thandler=handler; return old;
  37. }
  38.  
  39. /************************************************************************/
  40. /*    Purpose..:     Terminate exception handling                            */
  41. /*    Input....:    ---                                                        */
  42. /*    Return...:    --- (shall not return to caller)                        */
  43. /************************************************************************/
  44. extern void terminate()
  45. {
  46.     if(thandler) thandler(); abort();
  47. }
  48.  
  49. /************************************************************************/
  50. /*    Purpose..:     Set an unexpected handler function                        */
  51. /*    Input....:    pointer to unexpected handler function                    */
  52. /*    Return...:    ---                                                        */
  53. /************************************************************************/
  54. extern unexpected_handler set_unexpected(unexpected_handler handler)
  55. {
  56.     unexpected_handler old=uhandler; uhandler=handler; return old;
  57. }
  58.  
  59. /************************************************************************/
  60. /*    Purpose..:     Handle unexpected exception                                */
  61. /*    Input....:    ---                                                        */
  62. /*    Return...:    --- (shall not return to caller)                        */
  63. /************************************************************************/
  64. extern void unexpected()
  65. {
  66.     if(uhandler) uhandler(); terminate();
  67. }
  68.  
  69. /************************************************************************/
  70. /*    Purpose..:     Create a new exception state                            */
  71. /*    Input....:    pointer to uninitialized exception state                */
  72. /*    Input....:    pointer to excpetion buffer                                */
  73. /*    Return...:    ---                                                        */
  74. /************************************************************************/
  75. extern void __new_exception_state(ExceptionState *newp,char *buffer)
  76. {
  77.     newp->ldc_save    = 0;
  78.     newp->cb_save    = buffer;
  79.     newp->cvp_save    = 0;
  80.     newp->tt_save    = __throw_type;
  81.     newp->reserved    = 0;
  82. }
  83.  
  84. /************************************************************************/
  85. /*    Purpose..:     Switch to a new exception state                            */
  86. /*    Input....:    pointer to new exception state                            */
  87. /*    Input....:    pointer to exception state save buffer                    */
  88. /*    Return...:    ---                                                        */
  89. /************************************************************************/
  90. extern void __switch_exception_state(ExceptionState *newp,ExceptionState *savep)
  91. {
  92.     //    save current state
  93.     savep->ldc_save    = __local_destructor_chain;
  94.     savep->cb_save    = __catch_buffer;
  95.     savep->cvp_save    = __catch_var_pointer;
  96.     savep->tt_save    = __throw_type;
  97.  
  98.     //    set new state
  99.     __local_destructor_chain    = newp->ldc_save;
  100.     __catch_buffer                = newp->cb_save;
  101.     __catch_var_pointer            = newp->cvp_save;
  102.     __throw_type                = newp->tt_save;
  103. }
  104.  
  105. /************************************************************************/
  106. /*    Purpose..:     Register a global object for later destruction            */
  107. /*    Input....:    pointer to global object                                */
  108. /*    Input....:    pointer to destructor function                            */
  109. /*    Input....:    pointer to global registration structure                */
  110. /*    Return...:    pointer to global object (pass thru)                    */
  111. /************************************************************************/
  112. extern void *__register_global_object(void *object,void *destructor,void *regmem)
  113. {
  114.     ((DestructorChain *)regmem)->next=__global_destructor_chain;
  115.     ((DestructorChain *)regmem)->destructor=destructor;
  116.     ((DestructorChain *)regmem)->object=object;
  117.     __global_destructor_chain=(DestructorChain *)regmem;
  118.  
  119.     return object;
  120. }
  121.  
  122. /************************************************************************/
  123. /*    Purpose..:     Register an automatic data object for later destruction    */
  124. /*    Input....:    pointer to automatic object                                */
  125. /*    Input....:    pointer to destructor function                            */
  126. /*    Input....:    pointer to ExceptionElement structure                    */
  127. /*    Return...:    pointer to automatic object (pass thru)                    */
  128. /************************************************************************/
  129. void *__register_auto_object(void *object,void *destructor,void *regmem)
  130. {
  131.     ((ExceptionElement *)regmem)->type                            = EET_AUTODESTROY;
  132.     ((ExceptionElement *)regmem)->next                            = __local_destructor_chain;
  133.     ((ExceptionElement *)regmem)->data.autodestroy.destructor    = destructor;
  134.     ((ExceptionElement *)regmem)->data.autodestroy.object        = object;
  135.     __local_destructor_chain=(ExceptionElement *)regmem;
  136.  
  137.     return object;
  138. }
  139.  
  140. /************************************************************************/
  141. /*    Purpose..:     Register a temporary data object for later destruction    */
  142. /*    Input....:    pointer to temporary object                                */
  143. /*    Input....:    pointer to destructor function                            */
  144. /*    Input....:    pointer to ExceptionElement structure                    */
  145. /*    Return...:    pointer to temporary object (pass thru)                    */
  146. /************************************************************************/
  147. extern void *__register_temp_object(void *object,void *destructor,void *regmem)
  148. {
  149.     ((ExceptionElement *)regmem)->type                            = EET_TEMPDESTROY;
  150.     ((ExceptionElement *)regmem)->next                            = __local_destructor_chain;
  151.     ((ExceptionElement *)regmem)->data.autodestroy.destructor    = destructor;
  152.     ((ExceptionElement *)regmem)->data.autodestroy.object        = object;
  153.     __local_destructor_chain=(ExceptionElement *)regmem;
  154.  
  155.     return object;
  156. }
  157.  
  158. /************************************************************************/
  159. /*    Purpose..:     Pre register a temporary data object                    */
  160. /*    Input....:    pointer to temporary object                                */
  161. /*    Input....:    pointer to destructor function                            */
  162. /*    Input....:    pointer to ExceptionElement structure                    */
  163. /*    Return...:    pointer ExceptionElement structure                        */
  164. /************************************************************************/
  165. extern void *__preregister_temp_object(void *object,void *destructor,void *regmem)
  166. {
  167. //
  168. //    Note:    This function is used to register an object that will be constructed
  169. //            by a return statement. The result of this function will be passed to
  170. //            the function return temp memory argument.
  171. //
  172.     ((ExceptionElement *)regmem)->type                            = EET_TEMPDESTROY;
  173.     ((ExceptionElement *)regmem)->next                            = __local_destructor_chain;
  174.     ((ExceptionElement *)regmem)->data.autodestroy.destructor    = destructor;
  175.     ((ExceptionElement *)regmem)->data.autodestroy.object        = object;
  176.     __local_destructor_chain=(ExceptionElement *)regmem;
  177.  
  178.     return regmem;
  179. }
  180.  
  181. /************************************************************************/
  182. /*    Purpose..:     Re-register a temporary data object                        */
  183. /*    Input....:    pointer to local ExceptionElement structure                */
  184. /*    Return...:    pointer to temporary object                                */
  185. /************************************************************************/
  186. extern void *__reregister_temp_object(void *regmem)
  187. {
  188. //
  189. //    Note:    This function will register a preregistered local object for destruction.
  190. //            It will be called before a return object is initialized via return <x>;
  191. //
  192.     ((ExceptionElement *)regmem)->type = EET_TEMPDESTROY;
  193.     return ((ExceptionElement *)regmem)->data.autodestroy.object;
  194. }
  195.  
  196. /************************************************************************/
  197. /* Purpose..: Destroy all constructed global objects                    */
  198. /* Input....: ---                                                        */
  199. /* Return...: ---                                                        */
  200. /************************************************************************/
  201. #ifndef __MC68K__        //    defined in 68K startup code
  202.  
  203. void __destroy_global_chain(void)
  204. {
  205.     DestructorChain    *gdc;
  206.  
  207.     while((gdc=__global_destructor_chain)!=0L)
  208.     {
  209.         __global_destructor_chain=gdc->next;
  210.         ((ConstructorDestructor)gdc->destructor)(gdc->object,-1);
  211.     }
  212. }
  213.  
  214. #endif
  215.  
  216. /************************************************************************/
  217. /*    Purpose..:     Destroy one or more temporary objects                    */
  218. /*    Input....:    pointer to last destroyed objects ExceptionElement        */
  219. /*    Return...:    ---                                                        */
  220. /************************************************************************/
  221. extern void __destroy_temp_objects(void *lastregmem)
  222. {
  223.     ExceptionElement    *eep,*neep;
  224.  
  225.     while((eep=__local_destructor_chain)!=0L)
  226.     {
  227.         if(eep->type==EET_TEMPDESTROY)
  228.         {
  229.             __local_destructor_chain=eep->next;
  230.             ((ConstructorDestructor)eep->data.autodestroy.destructor)(eep->data.autodestroy.object,-1);
  231.             if((void *)eep==lastregmem) return;
  232.         }
  233.         else break;
  234.     }
  235.  
  236.     __local_destructor_chain=eep;    //    this will remain the top element
  237.  
  238.     for(;;)
  239.     {
  240.         if((neep=eep->next)==0L) return;
  241.         if(neep->type==EET_TEMPDESTROY)
  242.         {
  243.             eep->next=neep->next;
  244.             ((ConstructorDestructor)neep->data.autodestroy.destructor)(neep->data.autodestroy.object,-1);
  245.             if((void *)neep==lastregmem) return;
  246.         }
  247.         else eep=neep;
  248.     }
  249. }
  250.  
  251. /************************************************************************/
  252. /*    Purpose..:     Destroy one or more automatic/temporary objects            */
  253. /*    Input....:    pointer to last destroyed objects ExceptionElement         */
  254. /*    Return...:    ---                                                        */
  255. /************************************************************************/
  256. extern void __destroy_autotemp_objects(void *lastregmem)
  257. {
  258.     ExceptionElement    *eep;
  259.  
  260.     while((eep=__local_destructor_chain)!=0L)
  261.     {
  262.         __local_destructor_chain=eep->next;
  263.         switch(eep->type)
  264.         {
  265.         case EET_AUTODESTROY:
  266.         case EET_TEMPDESTROY:
  267.             ((ConstructorDestructor)eep->data.autodestroy.destructor)(eep->data.autodestroy.object,-1);
  268.             break;
  269.  
  270. //        case EET_PREAUTODESTROY:
  271. //        case EET_CATCHBLOCK:
  272. //            break;
  273.         }
  274.         if((void *)eep==lastregmem) return;
  275.     }
  276. }
  277.  
  278. /************************************************************************/
  279. /*    Purpose..:     Destroy some constructed local objects                    */
  280. /*    Input....:    pointer to first non-destroyed ExceptionElement            */
  281. /*    Return...:    ---                                                        */
  282. /************************************************************************/
  283. extern void __destroy_autotemp_objects_to(void *lastregmem)
  284. {
  285.     ExceptionElement    *eep;
  286.  
  287.     while((eep=__local_destructor_chain)!=0L)
  288.     {
  289.         if((void *)eep==lastregmem) return;
  290.         __local_destructor_chain=eep->next;
  291.         switch(eep->type)
  292.         {
  293.         case EET_AUTODESTROY:
  294.         case EET_TEMPDESTROY:
  295.             ((ConstructorDestructor)eep->data.autodestroy.destructor)(eep->data.autodestroy.object,-1);
  296.             break;
  297.  
  298. //        case EET_PREAUTODESTROY:
  299. //        case EET_CATCHBLOCK:
  300. //            break;
  301.         }
  302.     }
  303. }
  304.  
  305. /************************************************************************/
  306. /* Purpose..: Destroy all constructed local objects                        */
  307. /* Input....: pointer to chain                                            */
  308. /* Return...: ---                                                        */
  309. /************************************************************************/
  310. extern void __destroy_local_chain(void)
  311. {
  312.     ExceptionElement    *eep;
  313.  
  314.     while((eep=__local_destructor_chain)!=0L)
  315.     {
  316.         __local_destructor_chain=eep->next;
  317.         switch(eep->type)
  318.         {
  319.         case EET_AUTODESTROY:
  320.         case EET_TEMPDESTROY:
  321.             ((ConstructorDestructor)eep->data.autodestroy.destructor)(eep->data.autodestroy.object,-1);
  322.             break;
  323.  
  324. //        case EET_PREAUTODESTROY:
  325. //        case EET_CATCHBLOCK:
  326. //            break;
  327.         }
  328.     }
  329. }
  330.  
  331. /************************************************************************/
  332. /* Purpose..: Dummy function (does nothing)                                */
  333. /* Input....: ---                                                        */
  334. /* Return...: ---                                                        */
  335. /************************************************************************/
  336. extern void __dummy(void)
  337. {
  338. }
  339.  
  340. /************************************************************************/
  341. /* Purpose..: Throw an exception                                        */
  342. /* Input....: pointer to thrown type id string (0: throw;)                */
  343. /* Return...: ---                                                        */
  344. /************************************************************************/
  345. extern void __throw(char *throwtype)
  346. {
  347.     ExceptionElement    *eep;
  348.     char                *cptr1,*cptr2;
  349.     CatchData            *catchdata;
  350.     long                offset;
  351.  
  352.     if(throwtype==0)
  353.     {    //    throw;
  354.         if((throwtype=__throw_type)==0) terminate();
  355.     }
  356.     else __throw_type=throwtype;
  357.  
  358.     for(eep=__local_destructor_chain; eep; eep=eep->next) if(eep->type==EET_CATCHBLOCK)
  359.     {
  360.         if((cptr2=eep->data.catchblock.catchtype)==0) goto catchit;        //    catch(...)
  361.         cptr1=throwtype;
  362.         switch(*cptr1)
  363.         {
  364.         case '*':
  365.         case '!':
  366.             if(*cptr1++==*cptr2++) for(;;)
  367.             {    //    class name compare loop
  368.                 if(*cptr1==*cptr2++)
  369.                 {
  370.                     if(*cptr1++=='!')
  371.                     {    //    class match found / get offset
  372.                         for(offset=0; *cptr1!='!';) offset=offset*10+*cptr1++-'0';
  373.                         goto catchit;
  374.                     }
  375.                 }
  376.                 else
  377.                 {
  378.                     while(*cptr1++!='!') ;                    //    skip class name
  379.                     while(*cptr1++!='!') ;                    //    skip offset
  380.                     if(*cptr1==0) break;                    //    break if no more class names
  381.                     cptr2=eep->data.catchblock.catchtype+1;    //    retry with next class name
  382.                 }
  383.             }
  384.             break;
  385.  
  386.         default:
  387.             for(; *cptr1==*cptr2; cptr1++,cptr2++) if(*cptr1==0) goto catchit;
  388.             break;
  389.         }
  390.     }
  391.     terminate();    //    no matching catcher found
  392.  
  393. catchit:
  394.     catchdata=eep->data.catchblock.catchdata;
  395.     switch(*throwtype)
  396.     {
  397.     case '!':    //    class match (directly adjust offset)
  398.         __catch_var_pointer=(char *)__catch_buffer+offset; break;
  399.  
  400.     case '*':    //    pointer match (create a pointer copy with adjusted offset)
  401.         __catch_var_pointer=(char *)__catch_buffer+sizeof(void *);
  402.         *(long *)__catch_var_pointer=*(long *)__catch_buffer+offset; break;
  403.  
  404.     default:    //    traditional match
  405.         __catch_var_pointer=__catch_buffer; break;
  406.     }
  407.  
  408.         //    destroy all temporary objects and remove catchers
  409.  
  410.     while(!eep->data.catchblock.catchdata->last_catch)
  411.     {    //    skip all catchers that belong to this catch block
  412.         if((eep=eep->next)==0 || eep->type!=EET_CATCHBLOCK) terminate();
  413.     }
  414.     __destroy_autotemp_objects(eep);
  415.  
  416.         //    longjmp to catcher
  417.  
  418.     __catch_jump(catchdata->catch_buffer,catchdata->catch_pc);
  419. }
  420.  
  421. /************************************************************************/
  422. /* Purpose..: Install an exception catcher                                */
  423. /* Input....: true: first catcher in a set of catchers                    */
  424. /* Input....: pointer to exception element (uninitialized)                */
  425. /* Input....: pointer to catch data structure (uninitialized)            */
  426. /* Input....: pointer to catch register buffer (initialized)            */
  427. /* Input....: pointer to catcher pc                                        */
  428. /* Input....: pointer to catcher type string                            */
  429. /* Return...: ---                                                        */
  430. /************************************************************************/
  431. extern void __install_catcher(long last_catch,ExceptionElement *eep,CatchData *catchdata,CatchRegBuffer *catch_buffer,void *catch_pc,char *catchtype)
  432. {
  433.     catchdata->catch_pc                = catch_pc;
  434.     catchdata->catch_buffer            = catch_buffer;
  435.     catchdata->last_catch            = last_catch;
  436.  
  437.     eep->type                        = EET_CATCHBLOCK;
  438.     eep->next                        = __local_destructor_chain;
  439.     eep->data.catchblock.catchtype    = catchtype;
  440.     eep->data.catchblock.catchdata    = catchdata;
  441.     __local_destructor_chain=eep;
  442. }
  443.  
  444. #if        defined(__MC68K__)
  445.  
  446. /************************************************************************/
  447. /* Purpose..: Save non-volatile registers into a buffer                    */
  448. /* Input....: pointer to catch register buffer                            */
  449. /* Return...: ---                                                        */
  450. /************************************************************************/
  451. extern asm void __setup_catchregbuffer(CatchRegBuffer *crp)
  452. {
  453.     movea.l    (sp)+,a1                //    pop return address into a1
  454.     movea.l    (sp),a0                    //    load crp into a0
  455.     movem.l    d3-d7/a2-a4/a6-a7,(a0)    //    save non-volatile registers
  456.     jmp        (a1)                    //    return to caller
  457. }
  458.  
  459. /************************************************************************/
  460. /* Purpose..: Restore non-volatile registers an d jump to catcher        */
  461. /* Input....: pointer to catch register buffer                            */
  462. /* Input....: pointer to catcher routine                                */
  463. /* Return...: --- (does not return to caller)                            */
  464. /************************************************************************/
  465. extern asm void __catch_jump(CatchRegBuffer *crp,void *pc)
  466. {
  467.     addq.l    #4,sp                    //    pop return address
  468.     movea.l    (sp)+,a0                //    pop crp into a0
  469.     movea.l    (sp),a1                    //    load pc into a1
  470.     movem.l    (a0),d3-d7/a2-a4/a6-a7    //    restore non-volatile registers
  471.     addq.l    #4,sp                    //    adjust stack pointer (remove __setup_catchregbuffer's crp)´
  472.     jmp        (a1)                    //    jump to catcher
  473. }
  474.  
  475. #elif    defined(__POWERPC__)
  476.  
  477. // ???
  478.  
  479. #elif    defined(__INTEL__)
  480.  
  481. // ???
  482.  
  483. #else
  484. #error
  485. #endif
  486.